#!/usr/bin/env python
# -*- coding:utf-8 -*-

__VERSION__ = '1.4.0'

import sys, os.path
import time
import traceback

logger_error = sys.stderr
logger_warn  = sys.stderr
logger_info  = sys.stderr
logger_debug = sys.stderr

logger_error_path = None
logger_warn_path  = None
logger_info_path  = None
logger_debug_path = None

logger_path = None
logger_date = None

def now() :
    return time.strftime('%Y-%m-%d %H:%M:%S ')

def today() :
    return time.strftime('%Y-%m-%d')

def setLogPath(path='.') :
    global logger_path
    logger_path = path

def rotate() :
    global logger_date, logger_path
    global logger_error_path, logger_warn_path, logger_info_path, logger_debug_path
    global logger_error, logger_warn, logger_info, logger_debug

    if logger_path is None :
        return
    else :
        if not os.path.isdir(logger_path) :
            # a single sink file point
            if logger_error and logger_error != sys.stderr : return
            fh_log = open(logger_path, 'a', 0)
            if not fh_log : return
            logger_error = fh_log
            logger_warn  = fh_log
            logger_info  = fh_log
            logger_debug = fh_log
            return

    day = today()
    if logger_date == day : return
    if (logger_date is not None) and (logger_date != day):
        for logger_fh in (logger_error, logger_warn, logger_info, logger_debug) :
            logger_fh.close()
        for logger_file in (logger_error_path, logger_warn_path, logger_info_path, logger_debug_path) :
            if logger_file and os.path.getsize(logger_file) < 1 :
                os.remove(logger_file)

    logger_date = day
    logger_error_path = '%s/error.log-%s' % (logger_path, logger_date)
    logger_warn_path  = '%s/warn.log-%s' % (logger_path, logger_date)
    logger_info_path  = '%s/info.log-%s' % (logger_path, logger_date)
    logger_debug_path = '%s/debug.log-%s' % (logger_path, logger_date)

    logger_error = open(logger_error_path, 'a', 0)
    logger_warn  = open(logger_warn_path,  'a', 0)
    logger_info  = open(logger_info_path,  'a', 0)
    logger_debug = open(logger_debug_path, 'a', 0)
    # rotate()

#######################################################################

def error(format, *args) :
    rotate()
    logger_error.write(now() + 'ERROR ')
    logger_error.write(format % args)
    logger_error.write('\n')

def warn(format, *args) :
    rotate()
    logger_warn.write(now() + 'WARN  ')
    logger_warn.write(format % args)
    logger_warn.write('\n')

def info(format, *args) :
    rotate()
    logger_info.write(now() + 'INFO  ')
    logger_info.write(format % args)
    logger_info.write('\n')

def exception() :
    rotate()
    logger_error.write(now() + 'EXCPT ')
    logger_error.write(''.join(traceback.format_exception(*sys.exc_info())))
    logger_error.write('\n')

def excpt() :
    rotate()
    logger_error.write(now() + 'EXCPT ')
    nil, t, v, tbinfo = compact_traceback()
    logger_error.write('%s:%s %s' % (t, v, tbinfo))
    logger_error.write('\n')


debugable = False
def debug(format, *args) :
    rotate()
    global  debugable
    if debugable :
        filename, lineno, module, function = __tracestack()
        logger_debug.write(now() + '%s:%d DEBUG ' % (filename, lineno))
        logger_debug.write(format % args)
        logger_debug.write('\n')
    # debug()

def enableDebug() :
    global  debugable
    debugable = True
    # enableDebug()
def disableDebug() :
    global  debugable
    debugable = False
    # disableDebug()


def __tracestack() :
    stack = traceback.extract_stack()
    LAYER = -3
    filename = os.path.basename(stack[LAYER][0])
    lineno   = stack[LAYER][1]
    module   = stack[LAYER][2]
    function = stack[LAYER][3]
    return  (filename, lineno, module, function)

#######################################################################

def compact_traceback():
    '''
    nil, t, v, tbinfo = compact_traceback()
    log.error('trackback exception : (%s:%s %s)', t, v, tbinfo)
    '''
    t, v, tb = sys.exc_info()
    tbinfo = []
    assert tb # Must have a traceback
    while tb:
        tbinfo.append((
            tb.tb_frame.f_code.co_filename,
            tb.tb_frame.f_code.co_name,
            str(tb.tb_lineno)
            ))
        tb = tb.tb_next

    # just to be safe
    del tb

    file, function, line = tbinfo[-1]
    info = ' '.join(['[%s|%s|%s]' % x for x in tbinfo])
    return (file, function, line), t, v, info

#######################################################################


__all__ = [ 'error', 'warn', 'info', 'debug', 'exception' ]

